/*
 * Copyright 2004-2005 asoft
 * 本软件及其所有拷贝的名称，与光盘上或本软件中注明的公司同在。
 * 本软件及文档享有版权，并受国家版权法及国际协约条款的保护。
 * 您不可以从本软件中去掉其版权声明；并保证为本软件的拷贝（本部或部分）* 复制版权声明。
 * 您同意制止以任何形式非法拷贝本软件及文档。
 * 版权信息参见：
 *      http://www.asoft.cn/licenses
 */

package com.asoft.common.util.mvc.formbean;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.jdom.Element;
import org.springframework.context.ApplicationContext;

import com.asoft.common.util.mvc.config.DataSource;
import com.asoft.common.util.mvc.config.FormBeanConfigReader;
import com.asoft.common.util.mvc.config.NoSuchElementException;
import com.asoft.common.util.mvc.config.ObjectCastorConfigReader;
import com.asoft.common.util.mvc.config.XmlFormatException;
import com.asoft.common.util.mvc.objectcast.AbstractCastor;
import com.asoft.common.util.mvc.valid.BooleanCalculator;
import com.asoft.common.util.mvc.valid.ConfigFileFormatException;
import com.asoft.common.util.mvc.valid.UserValidator;
import com.asoft.common.util.mvc.valid.ValidatedResult;

/**
 * 从request里面获取值来构造bean(TO)实例
 * 1. 从ConfigReader里面读取formbean信息
 * 2. 验证request里面的值（结合BooleanCaculator）
 * 3. 生成bean实例
 *
 * author: amon_lei created in ：2005-4-6 22:03
 */

public class FormBeanMaker
{

        static Logger logger = Logger.getLogger(FormBeanMaker.class);

        private DataSource ds;

        private HttpServletRequest request;

        // service element
        private Element serviceEle;

        // form beans detail <model>
        //                      <services>
        //                      <formbeans>
        private FormBeanConfigReader fbDetailReader;

        private ObjectCastorConfigReader occReader;

        // 校验结果存放
        private ValidatedResult vr ;

        private static Map cacheOfCastor;

        private Map utils;

        static
        {
                cacheOfCastor = new HashMap();
        }

        public FormBeanMaker(HttpServletRequest request,
                             Element serviceEle,
                             FormBeanConfigReader fbDetailReader,
                             ApplicationContext applicationContext)
          throws XmlFormatException
        {
                this.ds = new DataSource(request);
                this.request = request;
                this.serviceEle = serviceEle;
                this.occReader = new ObjectCastorConfigReader();
                this.vr = new ValidatedResult();
                this.fbDetailReader = fbDetailReader;
                // 初始化功能包
                this.initUtils(applicationContext);
        }

        public void initUtils(ApplicationContext applicationContext)
        {

                this.utils = new HashMap();
                this.utils.put("${applicationContext}",
                               applicationContext);
        }

        /**
         * 校验通过返回formbean
         */
        public Object[] making()
          throws NoSuchElementException,
                 XmlFormatException,
                 ConfigFileFormatException,
                 Exception
        {
                Element validateEle = this.serviceEle.getChild("validate");
                if(validateEle != null)
                {
                        if(validateEle.getChild("formbean") != null)
                        {
                                logger.debug("调用用户声明校验脚本");
                                List fbEles = validateEle.getChildren("formbean");
                                for(int i = 0; i < fbEles.size(); i ++)
                                {
                                        Element fbEle = (Element)fbEles.get(i);
                                        return this.makeFB(fbEle);
                                }
                        }
                        if(validateEle.getChild("refBean") != null)
                        {
                                String refBeanId = validateEle.getChild("refBean").getText();
                                ApplicationContext applicationContext = (ApplicationContext)this.utils.get("${applicationContext}");
                                UserValidator uv = (UserValidator)applicationContext.getBean(refBeanId);
                                uv.validing(this.request,this.vr,new String[0]);
                                return null;
                                
                        }
                        if(validateEle.getChild("class") != null)
                        {
                                String userValiClass = validateEle.getChild("class").getText();
                                List paramEles = validateEle.getChildren("param");
                                String[] params = null;
                                if(paramEles != null)
                                {
                                        params = new String[paramEles.size()];
                                        for(int i = 0; i < paramEles.size(); i ++)
                                        {
                                                Element paramEle = (Element)paramEles.get(i);
                                                params[i] = paramEle.getText();
                                        }
                                }
                                else
                                {
                                        params = new String[0];
                                }
                                logger.debug("调用用户自定义校验类" + userValiClass);
                                Class cl = Class.forName(userValiClass);
                                logger.debug("实例化");
                                UserValidator uv = (UserValidator)cl.newInstance();
                                logger.debug("给用户自定义类注入spring‘s applicationContext");
                                uv.setApplicationContext((ApplicationContext)this.utils.get("${applicationContext}"));
                                logger.debug("开始校验");
                                uv.validing(this.request,this.vr,params);
                                return null;
                        }
                        throw new UnsupportedOperationException("<validate> 下面 没有标签了 ？？？");
                }
                return null;
        }

        // 构造formbean 放到request里面,key是　formbean 的　className
        private Object[] makeFB(Element fbEle)
          throws NoSuchElementException,
                 XmlFormatException,
                 ConfigFileFormatException,
                 Exception

        {
                String fbId = fbEle.getAttributeValue("id");
                String fbName = fbEle.getAttributeValue("ref");
                Element fbDetailEle = this.fbDetailReader.getFormBeanDetailEleById(fbName);
                String fbClassName = fbDetailEle.getChild("class").getText();
                logger.info("构造formbean " + fbClassName);
                Class cls = Class.forName(fbClassName);
                Object fbObj = cls.newInstance();
                // 构造field
                List fieldEles = fbEle.getChildren("field");
                for(int i = 0; i < fieldEles.size(); i ++)
                {
                        Element fieldEle = (Element)fieldEles.get(i);
                        this.makeFieled(fbObj,fieldEle);
                }
                logger.info("构造完毕,放入 request.Attribute, key 是 " + fbClassName);
                // logger.debug(fbObj.toString());
                if(fbId == null)
                {
                        return new Object[] {fbClassName,fbObj};
                }
                else
                {
                        return new Object[] {fbId,fbObj};
                }
        }

        private void makeFieled(Object fbObj,Element fieldEle)
          throws NoSuchElementException,
                 XmlFormatException,
                 ConfigFileFormatException,
                 Exception
        {
                // 校验
                String fieldName = fieldEle.getAttributeValue("id");
                logger.info("1.  构造 field " + fieldName);
                logger.debug("2.  获取fieldName & regKey & from  ...");
                String fieldNameFLUC = this.firstLetterUpperCase(fieldName);
                String regKey  = fieldEle.getAttributeValue("regkey");
                String fromType = fieldEle.getAttributeValue("from");
                String errMess ;
                Element errMessEle = fieldEle.getChild("errMess");
                if(errMessEle != null)
                        errMess = errMessEle.getText();
                else
                        errMess = "";
                Object regValue = this.ds.getValue(fromType,regKey);
                // 设置值
                this.vr.setValue(regKey,regValue);
                logger.debug("3.  实例化BC");
                BooleanCalculator bc = new BooleanCalculator(fieldEle,regValue,ds,this.utils);
                try
                {
                        if(bc.start())
                        {
                                logger.debug("4.  校验通过");
                                if(fieldEle.getChild("castor") != null)
                                {
                                        // 校验通过
                                        Method getM = fbObj.getClass().getMethod("get" + fieldNameFLUC ,new Class[]{}) ;
                                        Method setM = fbObj.getClass().getMethod("set" + fieldNameFLUC ,new Class[]{getM.getReturnType()}) ;
                                        logger.debug("4.1  给form bean 的" + fieldName + " 附值 " + regValue);
                                        // 类型转换器实例化
                                        AbstractCastor castor = this.getCastor(fieldEle.getChild("castor").getAttributeValue("ref"));
                                        // 转换器参数值
                                        List paramValues = null;
                                        List params = fieldEle.getChild("castor").getChildren("param");
                                        if(params != null)
                                        {
                                                paramValues = new Vector(params.size());
                                                for(int i = 0; i < params.size(); i ++)
                                                {
                                                        Element param = (Element)params.get(i);
                                                        if(this.utils.get(param.getText()) == null)
                                                                paramValues.add(param.getText());
                                                        else
                                                                paramValues.add(this.utils.get(param.getText()));
                                                }
                                        }
                                        setM.invoke(fbObj,new Object[]{castor.casting(regValue,paramValues)});
                                }
                                
                        }
                        else
                        {
                                logger.debug("4.  校验不通过 " + errMess);
                                // @todo : 校验不通过
                                this.vr.setErrMess(regKey,errMess);
                        }
                }
                catch(IllegalAccessException iae)
                {
                        logger.error("构造formbean 异常： 类成员" + fieldName + "对应的get" + fieldNameFLUC + "()、set" + fieldNameFLUC + "() 不允许访问,是否将其设置为 public");
                        iae.printStackTrace();
                }
                catch(InvocationTargetException ivte)
                {
                        logger.error("构造formbean 异常： 类成员" + fieldName + "对应的get" + fieldNameFLUC + "()、set" + fieldNameFLUC + "() 调用失败");
                        ivte.printStackTrace();
                }
                catch(NoSuchMethodException nsme)
                {
                        logger.error("构造formbean 异常： 类成员" + fieldName + "对应的get" + fieldNameFLUC + "()、set" + fieldNameFLUC + "() 不存在");
                        nsme.printStackTrace();
                }
                catch(ClassNotFoundException cbfe)
                {
                        logger.error("类查找失败" );
                        cbfe.printStackTrace();
                }
        }

        // 头个字母大写化，　for bean getter setter
        private String firstLetterUpperCase(String str)
        {
                if(str.length() <= 0)
                {
                        logger.error("不可为''");
                        return "";
                }
                String firstL = str.substring(0,1).toUpperCase();
                return firstL + str.substring(1,str.length());
        }

        // 获取转换器
        private AbstractCastor getCastor(String castorId)
          throws XmlFormatException,
                 Exception


        {
                logger.debug(" 获取转换器");
                Object castorObj = cacheOfCastor.get(castorId);
                if( castorObj == null)
                {
                        logger.debug("     获取转换器缓存失败");
                        String clsName = this.occReader.getObjectCastorEle(castorId)
                                                       .getChild("class")
                                                       .getText();
                        try
                        {
                                Class occCls = Class.forName(clsName);
                                AbstractCastor castor = (AbstractCastor)occCls.newInstance();
                                synchronized(cacheOfCastor)
                                {
                                        cacheOfCastor.put(castorId,castor);
                                }
                                return castor;
                        }
                        catch(ClassNotFoundException cnfe)
                        {
                                logger.error("查找类转换器对应的类" + clsName + "失败,它真的存在吗？");
                                throw cnfe;
                        }
                        catch(InstantiationException ie)
                        {
                                logger.error("实例化转换器(" + clsName + ")失败");
                                throw ie;
                        }
                }
                else
                {
                        logger.debug(" 获取转换器缓存成功");
                        return (AbstractCastor)castorObj;
                }
        }

        public ValidatedResult getVR()
        {
                return this.vr;
        }
}
